﻿using AppGene.DataModel.Generators;
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Xml;

namespace AppGene.DataModel
{
    /// <summary>
    /// The class provides a logical database model.
    /// </summary>
    [DataContract]
    public class Database : IExtensibleDataObject
    {
        #region Constants
        /// <summary>
        /// The new GUID id function.
        /// </summary>
        public const string NewGuidID = "NEWID()";
        #endregion
        /// <summary>
        /// Create a Database instance.
        /// </summary>
        public Database()
        {
            this.tables = new LogicalTableCollection();
        }

        #region IExtensibleDataObject Implementation
        private ExtensionDataObject extensionData_Value;

        ExtensionDataObject IExtensibleDataObject.ExtensionData
        {
            get
            {
                return extensionData_Value;
            }
            set
            {
                extensionData_Value = value;
            }
        }
        #endregion

        [DataMember]
        private LogicalTableCollection tables;

        /// <summary>
        /// Get the tables collection.
        /// </summary>
        public LogicalTableCollection Tables
        {
            get
            {
                if (tables == null)
                {
                    this.tables = new LogicalTableCollection();
                }
                
                return tables;
            }
        }

        /// <summary>
        /// Creates a logical table and adds the table into the database instance.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public LogicalTable CreateTable(string name)
        {
            LogicalTable table = new LogicalTable(name);
            table.Database = this;

            this.Tables.Add(table);
            return table;
        }

        /// <summary>
        /// Deploys the database to a specific database server.
        /// </summary>
        public void Deploy()
        {

        }

        /// <summary>
        /// Gets the DDL script that generates the database in a database.
        /// </summary>
        public void GetDeployScript()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Gets the DDL script that upgrade the database in a database which has an earlier version of the database.
        /// </summary>
        public void GetUpgradeScript()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Saves a database instance into a specific file.
        /// </summary>
        /// <param name="database">The database instance.</param>
        /// <param name="path">The file path.</param>
        public static void Save(Database database, string path)
        {
            Save(database, path, false);
        }

        /// <summary>
        /// Saves a database instance into a specific file.
        /// </summary>
        /// <param name="database">The database instance.</param>
        /// <param name="path">The file path.</param>
        /// <param name="overWritten">Indicate if a file exists, it will be overwritten the file, or throw an expcetion.</param>
        public static void Save(Database database, string path, bool overWritten)
        {
            FileMode fileMode = FileMode.CreateNew;
            if (overWritten)
            {
                fileMode = FileMode.Create;
            }

            using (FileStream fs = new FileStream(path, fileMode))
            {
                using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(fs))
                {
                    DataContractSerializer ser = new DataContractSerializer(typeof(Database));
                    ser.WriteObject(writer, database);
                }
            }
        }

        /// <summary>
        /// Create a database instance from a specific file.
        /// </summary>
        /// <param name="path">The file path.</param>
        public static Database CreateDatabaseFromFile(string path)
        {
            // Deserialize an instance of the Person class  
            // from an XML file. First create an instance of the  
            // XmlDictionaryReader.
            using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
            {
                XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());

                // Create the DataContractSerializer instance.
                DataContractSerializer ser = new DataContractSerializer(typeof(Database));

                // Deserialize the data and read it from the instance.
                Database database = (Database)ser.ReadObject(reader);
                return database;
            }
        }

        /// <summary>
        /// Create a data model from a data model assembly.
        /// </summary>
        /// <param name="assembly">A data model assembly.</param>
        public void CreateDataModel(Assembly assembly)
        {
            DatabaseBuilder.BuildFromAssembly(this, assembly);
        }
    }
}
